package com.ruoyi.common.utils.socket;

import jakarta.websocket.server.PathParam;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.PingMessage;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.Map;
import java.util.concurrent.*;

@Component
public class WebSocketHandler extends TextWebSocketHandler {
    public static Log log = LogFactory.getLog(WebSocketHandler.class);
    private static final Map<String, WebSocketSession> connectedClients = new ConcurrentHashMap<>();
    //静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;
    //concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
    //在真正的使用中这个set的大小回应为非正规的退出（没调用close方法就关闭页面了），导致数量只增不减，后期需要一个客户端定期的一个心跳机制来控制删除一些已死的连接
    private static CopyOnWriteArraySet<WebSocketHandler> webSocketSet = new CopyOnWriteArraySet<WebSocketHandler>();

    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private WebSocketSession session;

    //用户id
    private String uid = "";
    //用户数所属部门
    private String depid = "";
    //用户所属部门
    private String roleid = "";

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        log.info("uri = " + session.getUri());
        String userId = session.getUri().toString().split("websocket/")[1];
        if (userId == null) {
            return;
        }
        userId = userId.replace("?", "");
        log.info("userId1 = " + userId);
        this.uid = userId;
        this.session = session;
        webSocketSet.add(this);
        connectedClients.put(userId, session);

        ScheduledFuture<?> pingTask = Executors.newScheduledThreadPool(1).scheduleAtFixedRate(() -> {
            try {
                if (session.isOpen()) {
                    session.sendMessage(new PingMessage());
                } else {
                    // 如果连接已关闭，取消任务
                    //this.cancel();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, 1, 30, TimeUnit.SECONDS); // 每30秒发送一次ping消息

        session.getAttributes().put("pingTask", pingTask);
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        // 处理接收到的消息
        try {
            String messageText = message.getPayload();
            System.out.println("Received message: " + messageText);

        }catch (Exception e){
            e.printStackTrace();
        }

    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        // 连接关闭后的逻辑
        System.out.println("WebSocket connection closed: " + session.getId());
        webSocketSet.remove(this);  //从set中删除

        ScheduledFuture<?> pingTask = (ScheduledFuture<?>) session.getAttributes().get("pingTask");
        if (pingTask != null) {
            pingTask.cancel(true);
        }
    }

    /**
     * 实现服务器主动推送给客户端
     */
    public void sendMessage(String message) throws IOException {
        this.session.sendMessage(new TextMessage(message));
    }

    /**
     * 发送消息到用户
     */
    public static void sendInfoToUser(String message, String uid) throws IOException {
        //uid = "123";
        log.info("sendInfoToUser = " + uid);
        log.info("sendInfoToUser = " + webSocketSet.size());
        for (WebSocketHandler item : webSocketSet) {
            try {
                //这里可以设定只推送给这个sid的，为null则全部推送
                if (uid == null || "null".equals(uid)) {
                    item.sendMessage(message);
                } else if (item.uid.equals(uid)) {
                    item.sendMessage(message);
                }
            } catch (IOException e) {
                log.error("sendInfoToUser", e);
                e.printStackTrace();
            }
        }
    }

    public static void sendUser(String userId, String message) throws IOException {
        log.info("sendUser = " + userId);
        log.info("sendUser message = " + message);
        if (userId == null) {
            return;
        }
        try {
            log.info("sendUser = 1");
            if (!connectedClients.containsKey(userId)) {
                return;
            }
            log.info("sendUser = 2");
            connectedClients.get(userId).sendMessage(new TextMessage(message));
            log.info("sendUser = 3");
        } catch (Exception e) {
            log.error("sendInfoToUser", e);
            e.printStackTrace();
        }
    }

    /**
     * 发送消息到部门
     */
    public static void sendInfoToDep(String message, @PathParam("depid") String depid) throws IOException {
        for (WebSocketHandler item : webSocketSet) {
            try {
                //这里可以设定只推送给这个sid的，为null则全部推送
                if (depid == null) {
                    item.sendMessage(message);
                } else if (item.depid.equals(depid)) {
                    item.sendMessage(message);
                }
            } catch (IOException e) {
                continue;
            }
        }
    }

    /**
     * 发送消息到角色
     */
    public static void sendInfoToRole(String message, @PathParam("roleid") String roleid) throws IOException {
        for (WebSocketHandler item : webSocketSet) {
            try {
                //这里可以设定只推送给这个sid的，为null则全部推送
                if (roleid == null) {
                    item.sendMessage(message);
                } else if (item.roleid.equals(roleid)) {
                    item.sendMessage(message);
                }
            } catch (IOException e) {
                continue;
            }
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketHandler.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketHandler.onlineCount--;
    }
}
